package a.a.a;

import android.app.Application;
import android.app.Instrumentation;
import android.content.pm.ApplicationInfo;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

public class SU {

    public static void appCreate(String className) {
        Object currentActivityThread = ism("android.app.ActivityThread",
                "currentActivityThread", new Class[]{}, new Object[]{});
        Object mBoundApplication = gfo("android.app.ActivityThread",
                currentActivityThread, "mBoundApplication");
        Object loadedApkInfo = gfo("android.app.ActivityThread$AppBindData",
                mBoundApplication, "info");
        sfo("android.app.LoadedApk", "mApplication", loadedApkInfo, null);
        Object oldApplication = gfo("android.app.ActivityThread",
                currentActivityThread, "mInitialApplication");
        ArrayList<Application> mAllApplications = (ArrayList<Application>) gfo("android.app.ActivityThread", currentActivityThread, "mAllApplications");
        mAllApplications.remove(oldApplication);

        ApplicationInfo appinfo_In_LoadedApk = (ApplicationInfo) gfo("android.app.LoadedApk",
                loadedApkInfo, "mApplicationInfo");
        ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo)
                gfo("android.app.ActivityThread$AppBindData", mBoundApplication, "appInfo");
        appinfo_In_LoadedApk.className = className;
        appinfo_In_AppBindData.className = className;
        Application app = (Application) im(
                "android.app.LoadedApk", "makeApplication", loadedApkInfo,
                new Class[]{boolean.class, Instrumentation.class},
                new Object[]{false, null});
        sfo("android.app.ActivityThread",
                "mInitialApplication", currentActivityThread, app);

        Map<String, ?> mProviderMap = (Map<String, ?>) gfo(
                "android.app.ActivityThread", currentActivityThread, "mProviderMap");
        Iterator it = mProviderMap.values().iterator();
        while (it.hasNext()) {
            Object providerClientRecord = it.next();
            Object localProvider = gfo(
                    "android.app.ActivityThread$ProviderClientRecord",
                    providerClientRecord, "mLocalProvider");
            sfo("android.content.ContentProvider",
                    "mContext", localProvider, app);
        }
        app.onCreate();
    }

    // invokeStaticMethod
    static Object ism(String className, String fieldName, Class[] classArray, Object[] objectArray) {
        try {
            Class c = Class.forName(className);
            Method m = c.getMethod(fieldName, classArray);
            return m.invoke(null, objectArray);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // invokeMethod
    static Object im(String className, String fieldName, Object obj, Class[] classArray, Object[] objectArray) {
        try {
            Class c = Class.forName(className);
            Method m = c.getMethod(fieldName, classArray);
            return m.invoke(obj, objectArray);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // getFieldObject
    static Object gfo(String className, Object obj, String fieldName) {
        try {
            Class c = Class.forName(className);
            Field f = c.getDeclaredField(fieldName);
            f.setAccessible(true);
            return f.get(obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // setFieldObject
    static void sfo(String className, String fieldName, Object obj, Object obj1) {
        try {
            Class c = Class.forName(className);
            Field f = c.getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(obj, obj1);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    int add(int a, int b){
        return a + b;
    }

}
